package com.lntea.netty.im.codec;

import com.lntea.netty.im.packet.Packet;
import com.lntea.netty.im.packet.common.Command;
import com.lntea.netty.im.serializer.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;

/**
 * rpc数据包编解码工具
 * 通信协议：魔数(4字节) + 版本号(1字节) + 序列化算法(1字节) + 指令(1字节) + 数据长度(4字节) + 数据(N字节)
 */
public class PacketCodeC {

    public static final int MAGIC_NUMBER = 0x12345678;

    public static PacketCodeC INSTANCE = new PacketCodeC();

    /**
     * 数据包编码
     * @param alloc
     * @param packet
     * @return
     */
    public ByteBuf encode(ByteBufAllocator alloc, Packet packet) {
        // 1.创建 ByteBuf对象
        ByteBuf buffer = alloc.buffer();
        return encode(buffer, packet);
    }

    /**
     * 数据包编码
     * @param packet
     * @return
     */
    public ByteBuf encode(ByteBuf buffer, Packet packet) {
        // 2.序列化数据包
        Serializer serializer = Serializer.DEFAULT;
        byte[] packetBytes = serializer.serializer(packet);

        // 3.数据包编码
        // 魔数(4字节) + 版本号(1字节) + 序列化算法(1字节) + 指令(1字节) + 数据长度(4字节) + 数据(N字节)
        buffer.writeInt(MAGIC_NUMBER);
        buffer.writeByte(packet.getVersion());
        buffer.writeByte(serializer.getSerializerAlgorithm());
        buffer.writeByte(packet.getCommand());
        buffer.writeInt(packetBytes.length);
        buffer.writeBytes(packetBytes);

        return buffer;
    }

    /**
     * 数据包解码
     * @param buffer
     * @return
     */
    public Packet decode(ByteBuf buffer) {

        // 跳过魔数
        buffer.skipBytes(4);
        // 跳过版本号
        buffer.skipBytes(1);
        // 序列化算法
        byte serializerAlgorithm = buffer.readByte();
        // 指令
        byte command = buffer.readByte();
        // 数据包长度
        int packetLength = buffer.readInt();

        // 数据包数据
        byte[] packetBytes = new byte[packetLength];
        buffer.readBytes(packetBytes);

        // 获取指令Class
        Class<? extends Packet> packetClazz = getRequestType(command);
        // 获取序列化对象
        Serializer serializer = getSerializer(serializerAlgorithm);

        // 反序列化
        Packet packet = serializer.deserializer(packetClazz, packetBytes);
        return packet;
    }

    /**
     * 获取序列化实现类
     * @param serializerAlgorithm
     * @return
     */
    private Serializer getSerializer(byte serializerAlgorithm) {
        return Serializer.SERIALIZER_MAP.get(serializerAlgorithm);
    }

    /**
     * 获取指令Class
     * @param command
     * @return
     */
    private Class<? extends Packet> getRequestType(byte command) {
        return Command.COMMAND_MAP.get(command);
    }
}
